#include "eudaq/Producer.hh"
#include "eudaq/RawDataEvent.hh"
#include "eudaq/Utils.hh"
#include "eudaq/Logger.hh"
#include "eudaq/OptionParser.hh"
#include "eudaq/counted_ptr.hh"

#include <stdio.h>
#include <stdlib.h>

using eudaq::RawDataEvent;

class NiProducer: public eudaq::Producer {
public:
	NiProducer(const std::string & runcontrol) :
		eudaq::Producer("MimosaNI", runcontrol), done(false), running(false), stopping(false) {
		configure = false;
		std::cout << "NI Producer was started successful " << std::endl;
	}
	void MainLoop() {
		do {
			if (!running) {
				eudaq::mSleep(50);
				continue;
			}
			if (running) {
				eudaq::RawDataEvent ev("NI", m_run, ++m_ev);
				unsigned size;
			    std::vector<int> tmp((size+3)/4);
			    for (size_t i = 0; i < tmp.size(); ++i) {
			      tmp[i] = std::rand();
			    }
			    ev.AddBlock(0, &tmp[0], size);
			    //ev.SetTag("Debug", "foo");
			    SendEvent(ev);
			}
		} while (!done);
	}
	virtual void OnConfigure(const eudaq::Configuration & param) {
		try {
			std::cout << "Configuring ...(" << param.Name() << ")" << std::endl;

			NiConfig = false;

			if (NiConfig){
				std::cout << "NI crate was Configured with ERRORs " << param.Name() << " " << std::endl;
				SetStatus(eudaq::Status::LVL_ERROR, "Configuration Error");
			}
			else {
				std::cout << "... was Configured " << param.Name() << " " << std::endl;
				EUDAQ_INFO("Configured (" + param.Name() + ")");
				SetStatus(eudaq::Status::LVL_OK, "Configured (" + param.Name() + ")");
			}
		} catch (const std::exception & e) {
			printf("Caught exception: %s\n", e.what());
			SetStatus(eudaq::Status::LVL_ERROR, "Configuration Error");
		} catch (...) {
			printf("Unknown exception\n");
			SetStatus(eudaq::Status::LVL_ERROR, "Configuration Error");
		}
	}
	virtual void OnStartRun(unsigned param) {
		try {
			m_run = param;
			m_ev = 0;
			std::cout << "Start Run: " << param << std::endl;

			eudaq::RawDataEvent ev(RawDataEvent::BORE("NI", m_run));

			ev.SetTag("DET", "MIMOSA26");
			ev.SetTag("MODE", "ZS2");
			ev.SetTag("BOARDS", NumBoards);

			SendEvent(ev);
			eudaq::mSleep(500);

			running = true;

			SetStatus(eudaq::Status::LVL_OK, "Started");
		} catch (const std::exception & e) {
			printf("Caught exception: %s\n", e.what());
			SetStatus(eudaq::Status::LVL_ERROR, "Start Error");
		} catch (...) {
			printf("Unknown exception\n");
			SetStatus(eudaq::Status::LVL_ERROR, "Start Error");
		}
	}
	virtual void OnStopRun() {
		try {
			std::cout << "Stop Run" << std::endl;


			running = false;
			eudaq::mSleep(100);
			// Send an EORE after all the real events have been sent
			// You can also set tags on it (as with the BORE) if necessary
			SetStatus(eudaq::Status::LVL_OK, "Stopped");
			SendEvent(eudaq::RawDataEvent::EORE("NI", m_run, ++m_ev));

		} catch (const std::exception & e) {
			printf("Caught exception: %s\n", e.what());
			SetStatus(eudaq::Status::LVL_ERROR, "Stop Error");
		} catch (...) {
			printf("Unknown exception\n");
			SetStatus(eudaq::Status::LVL_ERROR, "Stop Error");
		}
	}
	virtual void OnTerminate() {
		std::cout << "Terminate (press enter)" << std::endl;
		done = true;

		eudaq::mSleep(1000);
	}
private:
	unsigned m_run, m_ev;
	bool done, running, stopping,  configure;
	struct timeval tv;
	counted_ptr<NiController> ni_control;

	bool NiConfig;

};
// ----------------------------------------------------------------------
int main(int /*argc*/, const char ** argv) {
	std::cout << "Start Producer \n" << std::endl;

	eudaq::OptionParser op("EUDAQ NI Producer", "0.1", "The Producer task for the NI crate");
	eudaq::Option<std::string> rctrl(op, "r", "runcontrol", "tcp://localhost:44000", "address", "The address of the RunControl application");
	eudaq::Option<std::string> level(op, "l", "log-level", "NONE", "level", "The minimum level for displaying log messages locally");
	eudaq::Option<std::string> name(op, "n", "name", "NI", "string", "The name of this Producer");
	try {
		op.Parse(argv);
		EUDAQ_LOG_LEVEL(level.Value());
		NiProducer producer(rctrl.Value());
		producer.MainLoop();
		eudaq::mSleep(500);
	} catch (...) {
		return op.HandleMainException();
	}
	return 0;
}
